package xquery;

import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.w3c.dom.ls.LSSerializerFilter;

public class XPathData {
	private ArrayList<Node> list;
	private boolean bool;
	private String string;
	
	enum Type {LIST, BOOL, STRING, UNDEFINED}
	
	Type type;
	
	public XPathData() {
		type = Type.UNDEFINED;
	}
	
	public XPathData(ArrayList<Node> l) {
		set(l);
	}
	
	public XPathData(boolean b) {
		set(b);
	}
	
	public XPathData(String s) {
		set(s);
	}
	
	public void set(ArrayList<Node> l) {
		list = l;
		type = Type.LIST;
	}
	
	public void set(boolean b) {
		bool = b;
		type = Type.BOOL;
	}
	
	public void set(String s) {
		string = s;
		type = Type.STRING;
	}

	public ArrayList<Node> getList() {
		if(type == Type.LIST)
			return list;
		else
			assert(false);
		
		return null;
	}

	public boolean getBool() {
		switch(type) {
		case LIST:
			return !(list.isEmpty());
		case BOOL:
			return bool;
		case STRING:
			return string!=null && string.length() > 0;
		default:
			assert(false);
			return false;
		}
	}

	public String getString() {
		if(type == Type.STRING)
			return string;
		else if(type == Type.LIST) {
			if(list.size()>0)
			{
				return list.get(0).getTextContent();
			}
			else
			{
				return "";
			}
		}
		else
			assert(false);
		
		return null;
	}
	
	public String toString() {
		if(type == Type.BOOL)
			return "" + bool;
		else if(type == Type.STRING)
			return string;
		
		try {
			DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
	        DOMImplementationLS domImplLS = (DOMImplementationLS)registry.getDOMImplementation("LS");
			LSSerializer ser = domImplLS.createLSSerializer();
			ser.getDomConfig().setParameter("format-pretty-print", true);
			ser.getDomConfig().setParameter("xml-declaration", false);
			
			StringBuilder result = new StringBuilder();
			
			if(list != null)
			{
				for(Node n : list) {
					result.append( ser.writeToString(n) );
				}
			}
			
			return result.toString();
		}
		catch(Exception e)
		{
			e.printStackTrace();
			System.exit(1);
		}
		
		return null;
	}

	public boolean eq(XPathData result2)
	{
		if(type == Type.BOOL || result2.type == Type.BOOL) {
			return this.getBool() == result2.getBool();
		} else if(type == Type.STRING || result2.type == Type.STRING) {
			return getString().equals(result2.getString());
		} else {
			for(Node n1 : getList()) {
				for(Node n2 : result2.getList()){
					if(n1.isEqualNode(n2))
						return true;
				}
			}
			
			return false;
		}
	}
	
	public boolean is(XPathData result2)
	{
		if(type != result2.type)
			return false;
		
		switch(type) {
		case BOOL:
			return this.getBool() == result2.getBool();
		case STRING:
			return getString().equals(result2.getString());
		case LIST:
			for(Node n1 : getList()) {
				for(Node n2 : result2.getList()){
					if(n1.isSameNode(n2))
						return true;
				}
			}
			
		default:
			assert false;
			return false;
		}
	}
	
	/*public static boolean isEqual(Node n1, Node n2)
	{
		if(!n1.getNodeName().equals(n2.getNodeName()))
		{
			return false;
		}
		if(n1.getNodeType() != n2.getNodeType() )
		{
			return false;
		}
		String v1,v2;
		if(n1.getNodeType() == Node.TEXT_NODE)
		{
			
			v1 = n1.getNodeValue().trim();
			v2 = n2.getNodeValue().trim();
			if(!v1.equals(v2))
			{
				return false;
			}
		}
		int childCount1, childCount2;
		NodeList children1, children2;
		Node child1, child2;
		children1 = n1.getChildNodes();
		children2 = n2.getChildNodes();
		childCount1 = children1.getLength();
		childCount2 = children2.getLength();
		if(childCount1 != childCount2)
		{
			return false;
		}
		for(int i=0;i<childCount1;i++)
		{
			child1 = children1.item(i);
			child2 = children2.item(i);
			if(!isEqual(child1,child2))
			{
				return false;
			}
		}
		return true;
	}*/
}
